#include "building.h"
#include <QMessageBox>
#include "model.h"
#include "iostream"

#define RENDER 1
#define SELECT 2
#define BUFSIZE 512

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif

Building::Building(QWidget *parent) : QGLWidget(parent)
{
    setFocusPolicy(Qt::StrongFocus);
    selected = 0;
    frame = true;
    selectmode = RENDER;
    mode = GL_SMOOTH;
    object = 0;
    rotateX = 0.0;
    translateX = 0.0;
    translateY = 0.0;
    translateZ = -11.0;
    textureIDs = new GLuint[10];
    light1=true;
    light2=true;
    globallight=false;
}

Building::~Building()
{
}

void Building::initializeGL()
{
    glEnable(GL_TEXTURE_2D);                        // Enable Texture Mapping
    glShadeModel(GL_SMOOTH);                        // Enable Smooth Shading
    glClearDepth(1.0f);                         // Depth Buffer Setup
    glEnable(GL_DEPTH_TEST);                        // Enables Depth Testing
    glEnable(GL_COLOR_MATERIAL);
    glEnable (GL_LIGHTING);

    glEnable(GL_NORMALIZE);

    GLfloat shin[]= {1.2f};
    GLfloat amb[]= { 0.2, 0.2, 0.2, 1 };
    GLfloat diff[]={ 0.5, 0.5,0.5, 1 };
    GLfloat specular[]={0.0,0.0,0.0};

    glDepthFunc(GL_LEQUAL);                         // The Type Of Depth Testing To Do
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);          // Really Nice Perspective Calculations
    glClearColor(0.0f,0.0f,0.0f,1.0f); 		// Let OpenGL clear to black

    GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f };

    glLightfv(GL_LIGHT7, GL_AMBIENT, LightAmbient);

    glDisable(GL_COLOR_MATERIAL);





    xml.parse();
    object = makeObject();		// Generate an OpenGL display list

    std::cout<<"startx"<<xml.getStartX();
    camera.Move( F3dVector(xml.getStartX(), xml.getStartY(), xml.getStartZ() ));
    camera.setMin(xml.getMinX(),xml.getMinY(),xml.getMinZ());
    camera.setMax(xml.getMaxX(),xml.getMaxY(),xml.getMaxZ());
}

void Building::resizeGL(int w, int h)
{
    ratio = 1.0f * w / h;
    glViewport( 0, 0, (GLint)w, (GLint)h );
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();

    glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 1000.0 );

    glMatrixMode( GL_MODELVIEW );

}

void Building::paintGL()
{

    // picking
    if (selectmode == SELECT) {
        startPicking();
    }


    glShadeModel(mode);

    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
    glLoadIdentity();

    if(light1)
    {
        glEnable(GL_LIGHT0);
    }
    else
    {
        glDisable(GL_LIGHT0);
    }
    if(globallight)
    {
        glEnable(GL_LIGHT7);
    }
    else
    {
        glDisable(GL_LIGHT7);
    }
    if(light2)
    {
        glEnable(GL_LIGHT1);
        glEnable(GL_LIGHT2);
        glEnable(GL_LIGHT3);
        glEnable(GL_LIGHT4);
    }
    else
    {
        glDisable(GL_LIGHT1);
        glDisable(GL_LIGHT2);
        glDisable(GL_LIGHT3);
        glDisable(GL_LIGHT4);
    }

    camera.Render();

    // wired frame
    if (frame) {
        glDisable(GL_TEXTURE_2D);
        glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    }
    else {
        glEnable(GL_TEXTURE_2D);
        glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
    }


    glCallList(object);
    glCallList(xml.getlights());
    GLuint onclicklist=xml.getonclick().value(clickid);
    glCallList(onclicklist);
    // picking
    if (selectmode == SELECT) {
        stopPicking();
    }
}

GLuint Building::makeObject()
{
    GLuint list;

    list = glGenLists( 1 );

    glNewList( list, GL_COMPILE );

    glCallList(xml.getObject());

    glEndList();

    return list;
}

void Building::keyPressEvent(QKeyEvent *e)
{
    GLfloat stap = 0.1;
    bool update = false;


    if (e->key() == Qt::Key_Z)
    {
        camera.MoveForward(-1);
        update = true;
    }
    else if (e->key() == Qt::Key_S) {
        camera.MoveForward(1);
        update = true;
    }
    else if (e->key() == Qt::Key_Q)
    {
        camera.StrafeRight(-1);
        update = true;
    }
    else if (e->key() == Qt::Key_D) {
        camera.StrafeRight(1);
        update = true;
    }

    else if (e->key() == Qt::Key_F1) {
        frame = !frame;
        update = true;
    }
    else if (e->key() == Qt::Key_F2) {
        if(mode == GL_SMOOTH) {
            mode = GL_FLAT;
        }
        else {
            mode = GL_SMOOTH;
        }
        update = true;
    }
    else if(e->key()==Qt::Key_Escape)
    {
        exit(1);
    }
    else if(e->key()==Qt::Key_F11)
    {
        light1=!light1;
        update=true;
    }
    else if(e->key()==Qt::Key_F12)
    {
        light2=!light2;
        update=true;
    }
    else if(e->key()==Qt::Key_F9)
    {
        globallight=!globallight;
        update=true;
    }
    if (update) {
        repaint();
    }
}

void Building::LoadGLTextures(QString fileName)
{
    QString filePath(":/data/");
    filePath.append(fileName);

    QImage t;
    QImage b;

    if ( !b.load(filePath.toLatin1().data()))
    {
        b = QImage();
        b.fill(Qt::white);
    }

    t = QGLWidget::convertToGLFormat( b );

    glGenTextures( 10, textureIDs);
    glBindTexture ( GL_TEXTURE_2D, textureIDs[0]);

    glTexImage2D( GL_TEXTURE_2D, 0, 3, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
}



void Building::mouseReleaseEvent(QMouseEvent * event) {
    repaint();
}

void Building::wheelEvent(QWheelEvent * event)
{
    if(event->delta()>0)
    {
        camera.MoveForward(-2);
    }
    else if(event->delta()<0)
    {
        camera.MoveForward(2);
    }
    repaint();
}

void Building::mousePressEvent(QMouseEvent *event) {
    if(event->button() == Qt::LeftButton)
    {
        cursorX = QCursor::pos().x();
        cursorY = QCursor::pos().y();
        selectmode = SELECT;
        repaint();
    }

}

void Building::startPicking()
{
    GLint viewport[4];

    glSelectBuffer(BUFSIZE,selectBuf);

    glGetIntegerv(GL_VIEWPORT,viewport);

    glRenderMode(GL_SELECT);

    glInitNames();

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();

    gluPickMatrix(cursorX,viewport[3]-cursorY,5,5,viewport);

    glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 1000.0 );

    glMatrixMode(GL_MODELVIEW);

}

void Building::processHits(GLint hits, GLuint buffer[])
{

    GLint i, j, numberOfNames;
    GLuint names, *ptr, minZ,*ptrNames;

    ptr = (GLuint *) buffer;
    minZ = 0xffffffff;
    for (i = 0; i < hits; i++) {
        names = *ptr;
        ptr++;
        if (*ptr < minZ) {
            numberOfNames = names;
            minZ = *ptr;
            ptrNames = ptr+2;
        }

        ptr += names+2;
    }
    if (numberOfNames > 0) {
        ptr = ptrNames;
        for (j = 0; j < numberOfNames; j++,ptr++) {
            selected = *ptr;
            qDebug ("CLICK  %d ", selected);
            QHash<int,QString> l=xml.getIds();
            QString s=l.value(selected);
            std::cout<<"id:"<< s.toStdString()<<"\n";
            clickid=s;
        }
    }
    else {
        if (selected != 0) {
            selected = 0;
        }

        qDebug("NO KLICK");
    }


}

void Building::stopPicking()
{
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glFlush();
    hits = glRenderMode(GL_RENDER);
    if (hits != 0){
        processHits(hits,selectBuf);
    }
    else {
        if (selected != 0) {
            selected = 0;
        }
        qDebug("NO KLICK");
    }
    selectmode = RENDER;


}

void Building::mouseMoveEvent(QMouseEvent *event) {


}

void Building::moveEvent(QMoveEvent * event)
{
    std::cout<<"test"<<endl;
}


bool Building::eventFilter(QObject *obj, QEvent *event)
{
    if (event->type() == QEvent::MouseMove)
    {
        QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
        if(x==0)
        {
            x=mouseEvent->x();

        }
        else if(y==0)
        {
            y=mouseEvent->y();
        }
        else
        {

            int deltax=x-mouseEvent->x();

            int deltay=y-mouseEvent->y();

            camera.RotateX(deltay/2);

            camera.RotateY(deltax/2);
            x=mouseEvent->x();
            y=mouseEvent->y();
        }
        repaint();
    }
    return false;
}
